<?php
namespace Peas\Kernel\System;

use Peas\Config\Configure;
use Peas\Http\Session;
use Peas\Routing\Router;
use Peas\View\CornTemplate;

/**
 * Peas Framework
 *
 * Framework入口
 *
 * @author  Hongzan Zhang <zhanghongzan@163.com>
 * @version $Id$
 */
class Application
{
    /**
     * 存储全局变量
     *
     * @var array
     */
    private static $_global = [];

    /**
     * 模板引擎实例
     *
     * @var CornTemplate
     */
    private static $_templateInstance = NULL;


    /**
     * 创建应用实例
     */
    public function __construct()
    {
        $runtimePath = _PATH_STORAGE . '/framework/cache/~runtime.php';
        (_MODE == 'work' && is_file($runtimePath)) ? require $runtimePath : Runtime::build();
    }

    /**
     * 启动应用
     *
     * @return void
     */
    public function run()
    {
        date_default_timezone_set(Configure::get('_default.timezone'));                   // 设置系统时区
        set_exception_handler(['\Peas\Kernel\System\SystemHandler', 'exceptionHandler']); // 设置异常处理
        set_error_handler(['\Peas\Kernel\System\SystemHandler', 'errorHandler']);         // 设置错误处理

        Configure::get('_session.autoStart') and Session::start();
        self::_execute(Router::dispatch());
    }

    /**
     * 执行URL
     *
     * @param  string $url 要执行的URL
     * @return void
     */
    private static function _execute($url)
    {
        ActionContext::$url = $url;
        $cache = false;
        $cachePath = _PATH_STORAGE . '/framework/cache/~' . urlencode($url) . '.php';
        if (is_file($cachePath)) {
            $cache = include $cachePath;
        }

        $filters = [];
        if (!empty($cache)) {
            self::initActionContext($cache['path'], $cache['controller'], $cache['method'], $cache['view']);
            $filters = $cache['filters'];
        } elseif (!Runtime::matchActionFromUrl($url)) {
            self::to404($url);
        } else {
            $filters = self::_getFilters();
        }

        // 执行过滤器
        self::_doFilters($filters);

        $controller = ActionContext::$controller;
        if (empty($controller)) {
            $template = self::getTemplateInstance();
            $template->assign($_POST);
            $template->assign($_GET);
            $template->assign('_c', Configure::get());
            $template->assign('_g', Application::globalVar());
            $template->display(ActionContext::$view);

        } else {
            $method = ActionContext::$method;
            $controllerClass = new $controller();
            // 调用初始化方法
            if (method_exists($controllerClass, '_init')) {
                $controllerClass->_init();
            }
            // 检查是否可以直接读取缓存
            $cacheLife = isset($controllerClass->cacheLife[$method]) ? $controllerClass->cacheLife[$method] : CornTemplate::CACHELIFE_DEFAULT;
            if (ActionContext::$template->isCached(ActionContext::$view, ActionContext::$cacheId, $cacheLife)) {
                ActionContext::$template->display(ActionContext::$view, ActionContext::$cacheId, $cacheLife);
            } else {
                $controllerClass->{$method}();
            }
        }
        // 记录缓存数据
        if (_MODE == 'work' && empty($cache)) {
            Runtime::buildAction($cachePath, $filters);
        }
    }


    /**
     * 执行过滤器
     *
     * @param  array $filters 要执行的过滤器
     * @return void
     */
    private static function _doFilters($filters)
    {
        if (!empty($filters)) {
            foreach ($filters as $filterName) {
                if (method_exists($filterName, 'execute')) {
                    $filter = new $filterName();
                    $filter->execute();
                }
            }
        }
    }

    /**
     * 获取匹配的过滤器，仅获取不执行
     *
     * @return array 所有匹配的过滤器名
     */
    private static function _getFilters()
    {
        $filters = Configure::get('_filter');
        if (empty($filters)) {
            return [];
        }
        $matchFilters = [];
        foreach ($filters as $filter => $pattern) {
            if (empty($pattern) || (!empty($pattern['exec']) && preg_match($pattern['exec'], ActionContext::$path))
                || (!empty($pattern['jump']) && !preg_match($pattern['jump'], ActionContext::$path))) {
                $matchFilters[] = $filter;
            }
        }
        return $matchFilters;
    }


    /**
     * 初始化会话信息
     *
     * @param  string $path       URL完整路径
     * @param  string $controller 控制器带包名的完整路径
     * @param  string $method     方法名
     * @param  string $view       默认匹配视图路径
     * @return void
     */
    public static function initActionContext($path, $controller, $method, $view)
    {
        ActionContext::$controller = $controller;
        ActionContext::$path       = $path;
        ActionContext::$method     = $method;
        ActionContext::$template   = self::getTemplateInstance();
        ActionContext::$view       = $view;
        ActionContext::$cacheId    = substr(md5($_SERVER['REQUEST_URI']), 8, 16);
    }


    /**
     * 获取模板引擎实例
     *
     * @return CornTemplate
     */
    public static function getTemplateInstance()
    {
        if (self::$_templateInstance !== null) {
            return self::$_templateInstance;
        }
        $template = new CornTemplate(Configure::get('_template'));
        if (defined('TEMPLATE_THEME')) {
            $template->setTheme(TEMPLATE_THEME);
        }
        return self::$_templateInstance = $template;
    }

    /**
     * 404
     *
     * @param  string $url 错误访问的url
     * @return void
     */
    public static function to404($url = '')
    {
        $app404Function = Configure::get('_404.function');
        if (!empty($app404Function)) {
            $app404Function($url);
        }
        if (!headers_sent()) {
            header("HTTP/1.0 404 Not Found");
            header("Status: 404 Not Found");
        }
        if (empty(Configure::get('_404.page'))) {
            echo '404';
        } else {
            include Configure::get('_404.page');
        }
        exit;
    }

    /**
     * 500
     *
     * @param  string $errInfo 错误信息
     * @return void
     */
    public static function to500($errInfo = '')
    {
        $app500Function = Configure::get('_500.function');
        if (!empty($app500Function)) {
            $app500Function($errInfo);
        }
        if (!headers_sent()) {
            header("HTTP/1.x 500 Internal Server Error");
            header('Status: 500 Internal Server Error');
        }
        if (empty(Configure::get('_500.page'))) {
            echo '500';
        } else {
            include Configure::get('_500.page');
        }
        exit;
    }

    /**
     * 全局变量读取、设置，如果仅指定了变量名则返回该变量值，同时指定变量名和变量值则为设置变量
     *
     * @param  string $name  变量名
     * @param  mixed  $value 变量值
     * @return mixed
     */
    public static function globalVar($name = '', $value = '__PEAS__G__VAL__')
    {
        if ($value == '__PEAS__G__VAL__') {
            if (empty($name)) {
                return self::$_global;
            }
            return array_key_exists($name, self::$_global) ? self::$_global[$name] : null;
        }
        self::$_global[$name] = $value;
    }
}
